//
//  zen_game_touch.cpp
//  app-ios gl
//
//  Created by MeherTj on 2022/1/22.
//  Copyright © 2022 lover. All rights reserved.
//

#include "zen_game_touch.h"
#include "zen_game_activity.h"

namespace Zen
{
	namespace Game
	{
		void TouchHandle::Release()
		{
			auto me = GetSharedFromThis<TouchHandle>();
			if (me != nullptr)
			{
				Activity::Only()->GetTouchDispatcher()->RemoveTouchHandle(me);
			}
		}

		void TouchHandle::SetMultiTouch(bool v)
		{
			mMultiTouch = v;
		}

		bool TouchHandle::IsMultiTouch()
		{
			return mMultiTouch;
		}

		void TouchHandle::SetEnabled(bool v)
		{
			mIsEnabled = v;
		}

		bool TouchHandle::IsEnabled()
		{
			return mIsEnabled;
		}

		void TouchDispatcher::AddTouchHandle(std::shared_ptr<TouchHandle> handle, int priority, std::shared_ptr<Node> target, bool acceptMultiTouch)
		{
			if (handle == nullptr)
			{
				LogE("bind a null TouchHandle");
				return;
			}
			auto i = std::make_shared<TouchHandleStatus>();
			i->handle = handle;
			i->target = target;
			i->priority = priority;
			i->acceptMultiTouch = acceptMultiTouch;
			mTouchHandles.emplace_back(i);
			this->SetPriorityDirty();
		}

		void TouchDispatcher::RemoveTouchHandle(std::shared_ptr<TouchHandle> handle)
		{
			if (handle == nullptr)
			{
				LogE("remove a null TouchHandle");
				return;
			}

			for (auto iter = mTouchHandles.begin(); iter != mTouchHandles.end();)
			{
				if ((*iter)->handle == handle)
				{
					iter = mTouchHandles.erase(iter);
				}
				else
				{
					++iter;
				}
			}
			if (handle != nullptr && mAct->handle == handle) mAct.reset();
		}

		void TouchDispatcher::RemoveTouchHandleOnNode(std::shared_ptr<Node> attach)
		{
			if (mAct && mAct->target.lock() == attach)
			{
				mAct.reset();
			}
			for (auto i = mTouchHandles.begin(); i != mTouchHandles.end();)
			{
				if ((*i)->target.lock() == attach)
				{
					i = mTouchHandles.erase(i);
				}
				else
				{
					++i;
				}
			}
		}

		void TouchDispatcher::RemoveAllTouchHandles()
		{
			mTouchHandles.clear();
			mAct.reset();
		}

		auto TouchDispatcher::GetTouches() -> std::map<uint32_t, AppTouch> const&
		{
			return mTouches;
		}

		void TouchDispatcher::OnTouchDown(AppTouch const& touch)
		{
			mTouches[touch.no] = touch;

			if (mTouches.size() > 1)
			{
				if (!mAct || !mAct->acceptMultiTouch) return;
				auto handle = mAct->handle.get();

				if (!handle->IsEnabled() || !handle->OnTouchDown(touch))
				{
					mAct.reset();
				}
			}
			else
			{
				mMainTouch = touch.no;
				mAct.reset();
				this->ClearPriorityDirty();
				auto handles_copy = mTouchHandles;
				for (auto& i : handles_copy)
				{
					auto handle = i->handle.get();
					if (handle && handle->IsEnabled() && handle->OnTouchDown(touch))
					{
						mAct = i;
						break;
					}
				}
			}
		}
		void TouchDispatcher::OnTouchMove(AppTouch const& touch)
		{
			if (!mAct) return;

			mTouches[touch.no] = touch;

			if (mAct->acceptMultiTouch || mMainTouch == touch.no)
			{
				if (!mAct->handle->IsEnabled() || !mAct->handle->OnTouchMove(touch))
				{
					mAct.reset();
				}
			}
		}
		void TouchDispatcher::OnTouchUp(AppTouch const& touch)
		{
			if (mAct)
			{
				mTouches[touch.no] = touch;
				if (mAct->acceptMultiTouch || mMainTouch == touch.no)
				{
					if (mAct->handle->IsEnabled())
					{
						mAct->handle->OnTouchUp(touch);
					}
				}
				mAct.reset();
			}
			mTouches.clear();
		}
		void TouchDispatcher::OnTouchCancel(AppTouch const& touch)
		{
			if (mAct)
			{
				mTouches[touch.no] = touch;
				if (mAct->acceptMultiTouch || mMainTouch == touch.no)
				{
					if (mAct->handle->IsEnabled())
					{
						mAct->handle->OnTouchCancel(touch);
					}
				}
				mAct.reset();
			}
			mTouches.clear();
		}

		void TouchDispatcher::SetPriorityDirty()
		{
			mIsHandlePriorityDirty = true;
		}
		void TouchDispatcher::ClearPriorityDirty()
		{
			if (!mIsHandlePriorityDirty) return;
			mIsHandlePriorityDirty = false;

			auto comp = [](std::shared_ptr<TouchHandleStatus> a, std::shared_ptr<TouchHandleStatus> b) { return a->priority < b->priority; };
			std::stable_sort(mTouchHandles.begin(), mTouchHandles.end(), comp);
		}
	} // namespace Game
} // namespace Zen
